package com.code.manager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.code.AZPlan.model.po.WithdrawOrder;
import com.code.commons.constants.ServerConstants;
import com.code.commons.enums.ResultCode;
import com.code.commons.exceptions.BusinessException;
import com.code.commons.model.bo.ClientResponse;
import com.code.commons.util.RSAUtil;
import com.code.commons.util.StringUtil;
import com.code.config.profile.ProfileConfig;
import com.code.model.bo.wallet.CoinBalance;
import com.code.model.bo.wallet.DepositTran;
import com.code.model.bo.wallet.WithdrawTran;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * http调用的相关管理类
 *
 * @author tangyifei
 */
@Component
@Slf4j
public class HttpManager {

    @Value("${digital.manager.url}")
    private String url;

    @Value("${digital.manager.appKey}")
    private String appKey;

    @Value("${digital.manager.privateKey}")
    private String privateKey;

    @Value("${digital.manager.language}")
    private String language;

    @Value("${digital.manager.source}")
    private String source;

    @Value("${digital.manager.version}")
    private String version;

    @Autowired
    private RestTemplate restTemplate;

    @Resource
    private ProfileConfig profileConfig;

    private static final String LANGUAGE = "language";

    private static final String SOURCE = "source";

    private static final String COIN_TYPE = "coinType";

    private static final String COIN_ID = "coinId";

    private static final String VERSION = "version";

    private static final String HEADER = "header";

    private static final String BODY = "body";

    private static final String X_APP_KEY = "x_appkey";

    private static final String X_SIGNATURE = "x_signature";

    private static final String X_TIMESTAMP = "x_timestamp";

    private static final String ACCEPT = "Accept";

    private static final String ADDRESS = "Address";

    private static final String COIN_SYMBOL = "coinSymbol";

    private static final String FROM_ADDR = "fromAddr";

    private static final String TO_ADDR = "toAddr";

    private static final String STATE = "state";

    private static final String ORDER_ID = "orderId";

    private static final String WITHDRAW_AMOUNT = "withdrawAmount";

    private static final String WITHDRAW_TO_ADDR = "withdrawToAddr";

    /**
     * 获取币种地址
     *
     * @param coinType 币种类型
     * @return 币种地址
     */
    public String getCoinAddress(String coinType) {
        //设置请求参数
        Map<String, Object> postData = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> header = Maps.newHashMapWithExpectedSize(1 << 4);
        header.put(LANGUAGE, language);
        header.put(SOURCE, source);
        header.put(COIN_TYPE, coinType);
        if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 7L);
        }
        if (ServerConstants.BTC.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 1L);
        }
        if (ServerConstants.USDT.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 5L);
        }
        header.put(VERSION, version);
        postData.put(HEADER, header);
        String requestBody = JSONObject.toJSONString(postData);
        log.info("请求体数据：【{}】", requestBody);
        HttpEntity<String> formEntity = new HttpEntity<>(requestBody, getJsonHeader(requestBody));
        HttpMethod method = HttpMethod.POST;
        ResponseEntity<ClientResponse> response = restTemplate.exchange(url + "/coin_addresses", method, formEntity, ClientResponse.class);
//        String result = restTemplate.postForEntity(url, formEntity, String.class).getBody();
//        log.info("获取币种地址返回的响应结果：【{}】", JSONObject.toJSONString(result));
        ClientResponse body = response.getBody();
        int rtnCode = body.getRtnCode();
        if (rtnCode == 1) {
            String address = String.valueOf(body.getData());
            log.info("返回的地址：【{}】", address);
            return address;
        } else {
            throw new BusinessException(ResultCode.GET_COIN_ADDRESS_ERROR);
        }
    }

    /**
     * 校验相关币种地址
     *
     * @param coinType    币种类型
     * @param coinAddress 币种地址
     * @return 币种地址验证结果
     */
    public Boolean verifyCoinAddress(String coinType, String coinAddress) {
        if (StringUtil.isEmpty(coinAddress)) {
            return false;
        }
        //设置请求参数
        Map<String, Object> postData = Maps.newHashMapWithExpectedSize(1 << 4);
        //请求头部分
        Map<String, Object> header = Maps.newHashMapWithExpectedSize(1 << 4);
        header.put(LANGUAGE, language);
        header.put(SOURCE, source);
        header.put(COIN_TYPE, coinType);
        if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 7L);
        }
        if (ServerConstants.BTC.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 1L);
        }
        if (ServerConstants.USDT.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 5L);
        }
        header.put(VERSION, version);
        postData.put(HEADER, header);
        //请求体部分
        Map<String, Object> reqBody = Maps.newHashMapWithExpectedSize(1 << 4);
        reqBody.put(ADDRESS, coinAddress);
        postData.put(BODY, reqBody);
        String requestBody = JSONObject.toJSONString(postData);
        log.info("请求体数据：【{}】", requestBody);
        HttpEntity<String> formEntity = new HttpEntity<>(requestBody, getJsonHeader(requestBody));
        HttpMethod method = HttpMethod.POST;
        ResponseEntity<ClientResponse> response = restTemplate.exchange(url + "/coin_addr_verify", method, formEntity, ClientResponse.class);
        ClientResponse body = response.getBody();
        int rtnCode = body.getRtnCode();
        if (rtnCode == 1) {
            Boolean verifyResult = (Boolean) body.getData();
            log.info("地址验证结果：【{}】", verifyResult);
            return verifyResult;
        } else {
            throw new BusinessException(ResultCode.VERIFY_COIN_ADDRESS_ERROR);
        }
    }

    /**
     * 获取相关的币种余额
     *
     * @param coinType    币种类型
     * @param coinAddress 币种地址
     * @return 币种地址
     */
    public BigDecimal getCoinBalance(String coinType, String coinAddress) {
        //设置请求参数
        Map<String, Object> postData = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> header = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> reqBody = Maps.newHashMapWithExpectedSize(1 << 4);
        header.put(LANGUAGE, language);
        header.put(SOURCE, source);
        header.put(COIN_TYPE, coinType);
        if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 7L);
            reqBody.put(COIN_ID, 7L);
            reqBody.put(COIN_SYMBOL, ServerConstants.XWC);
        }
        header.put(VERSION, version);
        reqBody.put(ADDRESS.toLowerCase(), coinAddress);
        postData.put(HEADER, header);
        postData.put(BODY, reqBody);
        String requestBody = JSONObject.toJSONString(postData);
        log.info("请求体数据：【{}】", requestBody);
        HttpEntity<String> formEntity = new HttpEntity<>(requestBody, getJsonHeader(requestBody));
        HttpMethod method = HttpMethod.POST;
        ResponseEntity<ClientResponse> response = restTemplate.exchange(url + "/coin_hot_balance", method, formEntity, ClientResponse.class);
        ClientResponse body = response.getBody();
        int rtnCode = body.getRtnCode();
        if (rtnCode == 1) {
            CoinBalance coinBalance = (CoinBalance) body.getData();
            BigDecimal balance = coinBalance.getBalance();
            log.info("返回的余额：【{}】", balance);
            return balance;
        } else {
            throw new BusinessException(ResultCode.GET_COIN_BALANCE_ERROR);
        }
    }

    /**
     * 获取充值交易列表
     *
     * @param coinType    币种类型
     * @param coinAddress 币种地址
     * @param state       状态，0: init, 1: online(not in block), 2: pending(in block but not confirmed), 3: done 4. failed
     * @return 充值交易列表
     */
    public List<DepositTran> getDepositTranList(String coinType, String coinAddress, Integer state) {
        //设置请求参数
        Map<String, Object> postData = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> header = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> reqBody = Maps.newHashMapWithExpectedSize(1 << 4);
        header.put(LANGUAGE, language);
        header.put(SOURCE, source);
        header.put(COIN_TYPE, coinType);
        header.put(VERSION, version);
        postData.put(HEADER, header);
        if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
            reqBody.put(COIN_ID, 7L);
        }
        if (ServerConstants.BTC.equalsIgnoreCase(coinType)) {
            reqBody.put(COIN_ID, 1L);
        }
        if (ServerConstants.USDT.equalsIgnoreCase(coinType)) {
            reqBody.put(COIN_ID, 5L);
        }
        reqBody.put(TO_ADDR, coinAddress);
        reqBody.put(STATE, state);
        postData.put(BODY, reqBody);
        String requestBody = JSONObject.toJSONString(postData);
//        log.info("请求体数据：【{}】", requestBody);
        HttpEntity<String> formEntity = new HttpEntity<>(requestBody, getJsonHeader(requestBody));
        HttpMethod method = HttpMethod.POST;
        ResponseEntity<ClientResponse> response = restTemplate.exchange(url + "/get_deposit_trans", method, formEntity, ClientResponse.class);
        ClientResponse body = response.getBody();
        int rtnCode = body.getRtnCode();
        if (rtnCode == 1) {
            List<DepositTran> depositTranList = JSON.parseArray(JSON.toJSONString(body.getData()), DepositTran.class);
            String profile = profileConfig.getActiveProfile();
            if (!ServerConstants.PROD.equals(profile)) {
                log.info("返回的充值交易列表：【{}】", JSON.toJSONString(depositTranList));
            }
            return depositTranList;
        } else {
            throw new BusinessException(ResultCode.GET_DEPOSIT_LIST_ERROR);
        }
    }

    /**
     * 获取提币交易列表
     *
     * @param coinType 币种类型
     * @param orderId  提币订单主键
     * @return 充值交易列表
     */
    public List<WithdrawTran> getWithDrawTranList(String coinType, String orderId) {
        //设置请求参数
        Map<String, Object> postData = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> header = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> reqBody = Maps.newHashMapWithExpectedSize(1 << 4);
        header.put(LANGUAGE, language);
        header.put(SOURCE, source);
        if (StringUtil.isNotEmpty(coinType)) {
            header.put(COIN_TYPE, coinType);
        }
        header.put(VERSION, version);
        postData.put(HEADER, header);
        if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
            reqBody.put(COIN_ID, 7L);
        }
        if (ServerConstants.BTC.equalsIgnoreCase(coinType)) {
            reqBody.put(COIN_ID, 1L);
        }
        if (ServerConstants.USDT.equalsIgnoreCase(coinType)) {
            reqBody.put(COIN_ID, 5L);
        }
        //reqBody.put(FROM_ADDR, coinAddress);
        reqBody.put(ORDER_ID, orderId);
        postData.put(BODY, reqBody);
        String requestBody = JSONObject.toJSONString(postData);
        log.info("请求体数据：【{}】", requestBody);
        HttpEntity<String> formEntity = new HttpEntity<>(requestBody, getJsonHeader(requestBody));
        HttpMethod method = HttpMethod.POST;
        ResponseEntity<ClientResponse> response = restTemplate.exchange(url + "/get_withdraw_trans", method, formEntity, ClientResponse.class);
        ClientResponse body = response.getBody();
        int rtnCode = body.getRtnCode();
        if (rtnCode == 1) {
            List<WithdrawTran> withdrawTranList = JSON.parseArray(JSON.toJSONString(body.getData()), WithdrawTran.class);
            String profile = profileConfig.getActiveProfile();
            if (!ServerConstants.PROD.equals(profile)) {
                log.info("返回的提币交易列表：【{}】", JSON.toJSONString(withdrawTranList));
            }
            return withdrawTranList;
        } else {
            throw new BusinessException(ResultCode.GET_WITHDRAW_LIST_ERROR);
        }
    }

    /**
     * 发送提币请求任务
     *
     * @param withdrawOrder 提币订单PO对象
     * @return 结果
     */
    public String sendWithdrawTask(WithdrawOrder withdrawOrder) {
        //设置请求参数
        Map<String, Object> postData = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> header = Maps.newHashMapWithExpectedSize(1 << 4);
        Map<String, Object> reqBody = Maps.newHashMapWithExpectedSize(1 << 4);
        String coinType = withdrawOrder.getCoinType();
        header.put(LANGUAGE, language);
        header.put(SOURCE, source);
        header.put(COIN_TYPE, coinType);
        header.put(VERSION, version);
        if (ServerConstants.XWC.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 7L);
        }
        if (ServerConstants.BTC.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 1L);
        }
        if (ServerConstants.USDT.equalsIgnoreCase(coinType)) {
            header.put(COIN_ID, 5L);
        }
        postData.put(HEADER, header);
        reqBody.put(ORDER_ID, withdrawOrder.getId());
        reqBody.put(WITHDRAW_AMOUNT, withdrawOrder.getAmount());
        reqBody.put(WITHDRAW_TO_ADDR, withdrawOrder.getToAddr());
        postData.put(BODY, reqBody);
        String requestBody = JSONObject.toJSONString(postData);
        log.info("请求体数据：【{}】", requestBody);
        HttpEntity<String> formEntity = new HttpEntity<>(requestBody, getJsonHeader(requestBody));
        HttpMethod method = HttpMethod.POST;
        ResponseEntity<ClientResponse> response = restTemplate.exchange(url + "/coin_withdraw", method, formEntity, ClientResponse.class);
        ClientResponse body = response.getBody();
        int rtnCode = body.getRtnCode();
        if (rtnCode == 1) {
            String requestTaskId = String.valueOf(body.getData());
            log.info("返回的请求任务主键：【{}】", requestTaskId);
            return requestTaskId;
        } else {
            throw new BusinessException(ResultCode.GET_WITHDRAW_LIST_ERROR);
        }
    }

    /**
     * 构造http请求的头部信息
     *
     * @param requestBody 请求体数据
     * @return http头部信息
     */
    private HttpHeaders getJsonHeader(String requestBody) {
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add(ACCEPT, MediaType.APPLICATION_JSON.toString());
        headers.add(X_APP_KEY, appKey);
        StringBuilder sb = new StringBuilder(1 << 2);
        sb.append(appKey);
        String timeStamp = String.valueOf(System.currentTimeMillis());
        sb.append(timeStamp);
        sb.append(requestBody);
        String signature = getSignatureByPrivateKey(sb.toString());
        headers.add(X_SIGNATURE, signature);
        headers.add(X_TIMESTAMP, timeStamp);
        return headers;
    }

    /**
     * 使用私钥生成签名
     *
     * @param sign 签名字符串
     * @return 私钥生成签名
     */
    private String getSignatureByPrivateKey(String sign) {
        return RSAUtil.sign(privateKey, sign);
    }


}
